﻿#region License Information
// Copyright (c) 2005 - 2009, Allan Spartacus Mangune (allan@owlpal.com)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, 
// are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this list 
//   of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice, this list of 
//   conditions and the following disclaimer in the documentation and/or other materials provided 
//   with the distribution.
//
// * Neither the name of Owlpal nor the names of its contributors may be used to endorse or 
//   promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 
// BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Owlpal.Blogs.Models;

namespace Owlpal.Blogs.Repositories
{
    /// <summary>
    /// 
    /// </summary>
    public class BlogRepository : Repository<Owlpal.Blogs.Models.Blog>, IBlogRepository
    {
        public BlogRepository()
            : base(new Owlpal.Blogs.Repositories.Factories.DataContextFactory())
        {

        }

        #region Methods
        /// <summary>
        /// Saves a Blog.
        /// </summary>
        /// <param name="userID"></param>
        /// <returns></returns>
        public AddBlogStatus SaveBlog(Guid userID)
        {
            return AddBlogStatus.Added;
        }

        /// <summary>
        /// Creates a Blog.
        /// </summary>
        /// <returns>Returns the status of the Add operation.</returns>
        public AddBlogStatus SaveBlog(Owlpal.Blogs.Models.Blog blog)
        {
            AddBlogStatus status = AddBlogStatus.UnknownError;
            var existingBlog = base.dataContextFactory.Context.Blog.FirstOrDefault(b => b.Name == blog.Name);
            if (existingBlog == null)
            {
                Owlpal.Blogs.Repositories.Blog blogEntity = new Owlpal.Blogs.Repositories.Blog();
                SetBlogEntityProperties(blogEntity, blog);
                blogEntity.ID = blog.ID;
                blogEntity.Name = blog.Name;
                blogEntity.CreatedBy = (Guid)blog.Creator.ProviderUserKey;
                blogEntity.DateCreated = blog.CreationDate;
                blogEntity.DateUpdated = blog.LastUpdateDate;
                base.dataContextFactory.Context.AddToBlog(blogEntity);
                Owlpal.Blogs.Repositories.UserBlog userBlogEntity = new Owlpal.Blogs.Repositories.UserBlog();
                userBlogEntity.BlogReference.Value = blogEntity;
                userBlogEntity.UserID = blogEntity.CreatedBy;
                userBlogEntity.CreatedBy = blogEntity.CreatedBy;
                userBlogEntity.CreationDate = blog.CreationDate;
                userBlogEntity.LastUpdateDate = blog.LastUpdateDate;
                userBlogEntity.ID = Guid.NewGuid();
                userBlogEntity.IsPrimary = blog.IsPrimary;
                base.dataContextFactory.Context.AddToUserBlog(userBlogEntity);
                try
                {
                    SaveChanges();
                    status = AddBlogStatus.Added;
                }
                catch (Exception ex)
                {
                    status = AddBlogStatus.Failed;
                }
            }
            else
            {
                status = AddBlogStatus.AlreadyExist;
            }
            return status;
        }

        /// <summary>
        /// Updates the Blog.
        /// </summary>
        /// <returns>Returns the status of the Edit operation.</returns>
        public EditBlogStatus EditBlog(Owlpal.Blogs.Models.Blog blog)
        {
            EditBlogStatus status = EditBlogStatus.UnknownError;
            var blogEntity = base.dataContextFactory.Context.Blog.FirstOrDefault(c => c.ID == blog.ID);
            if (blogEntity != null)
            {
                SetBlogEntityProperties(blogEntity, blog);
                blogEntity.DateUpdated = blog.LastUpdateDate;
                blogEntity.UpdatedBy = (Guid)blog.Updator.ProviderUserKey;
                try
                {
                    base.SaveChanges();
                    status = EditBlogStatus.Edited;

                }
                catch (Exception)
                {
                    status = EditBlogStatus.Failed;
                }
            }
            else
            {
                status = EditBlogStatus.DoesNotExist;
            }
            return status;
        }

        /// <summary>
        /// Marks the record of Blog as deleted. 
        /// </summary>
        /// <returns>Returns the status of the Delete operation.</returns>
        public DeleteBlogStatus DeleteBlog(Guid id)
        {
            DeleteBlogStatus status = DeleteBlogStatus.UnknownError;
            var existingBlog = dataContextFactory.Context.Blog.FirstOrDefault(b => b.ID == id);
            if (existingBlog != null)
            {
                existingBlog.IsDeleted = true;
                existingBlog.DateUpdated = DateTime.Now;
                try
                {
                    SaveChanges();
                    status = DeleteBlogStatus.Deleted;

                }
                catch (Exception)
                {
                    status = DeleteBlogStatus.Failed;
                }
            }
            else
            {
                status = DeleteBlogStatus.DoesNotExist;
            }
            return status;
        }

        /// <summary>
        /// Permanently remove the record from the database.
        /// </summary>
        /// <returns>Returns the status of the Remove operation.</returns>
        public RemoveBlogStatus RemoveBlog(Guid id)
        {
            RemoveBlogStatus status = RemoveBlogStatus.UnknownError;
            var existingBlog = dataContextFactory.Context.Blog.FirstOrDefault(b => b.ID == id); //requires round trip ?
            if (existingBlog != null)
            {
                dataContextFactory.Context.DeleteObject(existingBlog);
                //TODO: all records related to the blog must also be permanently removed.
                try
                {
                    SaveChanges();
                    status = RemoveBlogStatus.Removed;
                }
                catch (Exception ex)
                {
                    status = RemoveBlogStatus.Failed;
                    throw ex;
                }
            }
            else
            {
                status = RemoveBlogStatus.DoesNotExist;
            }
            return status;
        }

        /// <summary>
        /// Loads a collection of Blog based on userID.
        /// </summary>
        /// <param name="userID">The unique ID of the blogs.</param>
        /// <returns>A collection of Blog.</returns>
        public List<Owlpal.Blogs.Models.Blog> FindAllByUserID(Guid userID)
        {
            List<Owlpal.Blogs.Models.Blog> blogs = new List<Owlpal.Blogs.Models.Blog>();
            var query = from b in dataContextFactory.Context.Blog
                        join ub in dataContextFactory.Context.UserBlog on b.ID equals ub.Blog.ID
                        where ub.UserID == userID
                        select new
                        {
                            b.ID,
                            b.Name,
                            b.Title,
                            b.Description
                        };
            foreach (var myBlog in query)
            {
                Owlpal.Blogs.Models.Blog blog = new Owlpal.Blogs.Models.Blog();
                blog.ID = myBlog.ID;
                blog.Title = myBlog.Title;
                blog.Name = myBlog.Name;
                blog.Description = myBlog.Description;
                blogs.Add(blog);
            }
            return blogs;
        }

        /// <summary>
        /// Loads a Blog based on its unique ID.
        /// </summary>
        /// <param name="id">The unique ID of the Blog.</param>
        /// <returns>The Blog.</returns>
        public Owlpal.Blogs.Models.Blog FindBlog(System.Guid ID)
        {
            Owlpal.Blogs.Models.Blog blog = null;
            Owlpal.Blogs.Repositories.Blog blogEntity = 
                dataContextFactory.Context.Blog.FirstOrDefault(c => c.ID == ID);
            if (blogEntity != null)
            {
                blog = SetBlogProperties(blogEntity);
            }
            return blog;
        }

        /// <summary>
        /// Loads an instance of Blog based on its Name.
        /// </summary>
        /// <param name="name">The unique ID of the Blog.</param>
        /// <returns>The Blog.</returns>
        public Owlpal.Blogs.Models.Blog FindBlogByName(string name)
        {
            Owlpal.Blogs.Models.Blog blog = null;
            Owlpal.Blogs.Repositories.Blog dataBlog = 
                dataContextFactory.Context.Blog.FirstOrDefault(b => b.Name.ToLower() == name.ToLower());
            if (dataBlog != null)
            {
                blog = SetBlogProperties(dataBlog);
            }
            return blog;
        }

        /// <summary>
        /// Loads a paginated collection of Blog based on userID.
        /// </summary>
        /// <param name="userID">The unique ID of the user.</param>
        /// <param name="pageIndex">The page index to start retrieving records.</param>
        /// <param name="pageSize">The number of records to retrieve in a given page.</param>
        /// <returns>A paginated collection of Blog.</returns>
        public List<Owlpal.Blogs.Models.Blog> FindAllBlogsByUserID(Guid userID, int pageIndex, int pageSize, out int count)
        {
            
            List<Owlpal.Blogs.Models.Blog> blogs = new List<Owlpal.Blogs.Models.Blog>();
            var query = from b in dataContextFactory.Context.Blog
                        join ub in dataContextFactory.Context.UserBlog on b.ID equals ub.Blog.ID
                        where ub.UserID == userID
                        select new
                        {
                            b.ID,
                            b.Name,
                            b.Title,
                            CreationDate = b.DateCreated
                        };
            int skip = Math.Max(pageSize * (pageIndex - 1), 0);
            query.Take(pageSize).Skip(skip);
            foreach (var dataBlog in query)
            {
                Owlpal.Blogs.Models.Blog blog = new Owlpal.Blogs.Models.Blog();
                blog.ID = dataBlog.ID;
                blog.Name = dataBlog.Name;
                blog.Title = dataBlog.Title;
                blog.CreationDate = dataBlog.CreationDate;
                blogs.Add(blog);
            }
            count = (from b in dataContextFactory.Context.Blog
                     join ub in dataContextFactory.Context.UserBlog on b.ID equals ub.Blog.ID
                     where ub.UserID == userID
                     select b.ID).Count();
            return blogs;
        }

        /// <summary>
        /// Sets the attributes of Blog entity.
        /// </summary>
        /// <param name="myBlog"></param>
        /// <param name="blog"></param>
        /// <returns></returns>
        private Owlpal.Blogs.Repositories.Blog SetBlogEntityProperties(Owlpal.Blogs.Repositories.Blog 
            blogEntity, Owlpal.Blogs.Models.Blog blog)
        {
            blogEntity.Description = blog.Description;
            blogEntity.Title = blog.Title;
            blogEntity.IsPrivate = blog.IsPrivate;
            blogEntity.CopyrightPeriod = blog.CopyrightPeriod;
            blogEntity.Theme = blog.Theme;
            blogEntity.EnableFeeder = blog.EnableFeeder;
            blogEntity.EnablePublishing = blog.EnablePublishing;
            blogEntity.EnableComment = blog.EnableComment;
            blogEntity.EnableTrackback = blog.EnableTrackback;
            blogEntity.EnablePing = blog.EnablePing;
            blogEntity.EnableEmailReferral = blog.EnableEmailReferral;
            blogEntity.EnableRichEditor = blog.EnableRichEditor;
            blogEntity.EnbleAnonymousCommentModeration = blog.EnbleAnonymousCommentModeration;
            blogEntity.EnableNewCommentNotification = blog.EnableNewCommentNotification;
            blogEntity.AllowHtmlInComment = blog.AllowHtmlInComment;
            blogEntity.AllowAnonymousComment = blog.AllowAnonymousComment;
            blogEntity.EmailAddressForCommentNotification = blog.EmailAddressForCommentNotification;
            blogEntity.EmailAddressForEntryCreation = blog.EmailAddressForEntryCreation;
            blogEntity.EntryDisplay = blog.EntryDisplayCount;
            blogEntity.EntryDisplayType = blog.EntryDisplayType;
            blogEntity.EntryDisplaySortOrder = blog.EntryDisplaySortOrder;
            blogEntity.DateLocale = blog.DateLocale;
            blogEntity.DefaultEntryStatus = blog.DefaultEntryStatus;
            blogEntity.LinkQuantity = blog.LinkQuantity;
            blogEntity.FeedQuantity = blog.FeedQuantity;
            blogEntity.CopyrightOwner = blog.CopyrightOwner;
            blogEntity.Timezone = blog.Timezone;
            blogEntity.IsDeleted = blog.IsDeleted;
            return blogEntity;
        }

        /// <summary>
        /// Sets the attributes of the Blog.
        /// </summary>
        /// <param name="blogEntity"></param>
        /// <returns></returns>
        private Owlpal.Blogs.Models.Blog SetBlogProperties(Owlpal.Blogs.Repositories.Blog blogEntity)
        {
            Owlpal.Blogs.Models.Blog blog = new Owlpal.Blogs.Models.Blog();
            blog.ID = blogEntity.ID;
            blog.Name = blogEntity.Name;
            blog.Description = blogEntity.Description;
            blog.IsPrivate = blogEntity.IsPrivate;
            blog.Theme = blogEntity.Theme;
            blog.EnableFeeder = blogEntity.EnableFeeder;
            blog.EnablePublishing = blogEntity.EnablePublishing;
            blog.EnableComment = blogEntity.EnableComment;
            blog.EnableTrackback = blogEntity.EnableTrackback;
            blog.EnablePing = blogEntity.EnablePing;
            blog.EnableEmailReferral = blogEntity.EnableEmailReferral;
            blog.EnableRichEditor = blogEntity.EnableRichEditor;
            blog.EnbleAnonymousCommentModeration = blogEntity.EnbleAnonymousCommentModeration;
            blog.EnableNewCommentNotification = blogEntity.EnableNewCommentNotification;
            blog.AllowHtmlInComment = blogEntity.AllowHtmlInComment;
            blog.AllowAnonymousComment = blogEntity.AllowAnonymousComment;
            blog.EmailAddressForCommentNotification = blogEntity.EmailAddressForCommentNotification;
            blog.EmailAddressForEntryCreation = blogEntity.EmailAddressForEntryCreation;
            blog.EntryDisplayCount = blogEntity.EntryDisplay;
            blog.EntryDisplayType = blogEntity.EntryDisplayType;
            blog.EntryDisplaySortOrder = blogEntity.EntryDisplaySortOrder;
            blog.DateLocale = blogEntity.DateLocale;
            blog.CopyrightOwner = blogEntity.CopyrightOwner;
            blog.CopyrightPeriod = blogEntity.CopyrightPeriod;
            blog.DefaultEntryStatus = blogEntity.DefaultEntryStatus;
            blog.LinkQuantity = blogEntity.LinkQuantity; 
            blog.FeedQuantity = blog.FeedQuantity; 
            blog.Timezone = blogEntity.Timezone;
            blog.IsDeleted = blogEntity.IsDeleted;
            blog.LastUpdateDate = blogEntity.DateUpdated;
            blog.CreationDate = blogEntity.DateCreated;
            return blog;
        }
        #endregion
    }
}
